import 'package:flutter/material.dart';

import 'net_code.dart';
import 'net_request_interceptor.dart';
import 'result_data.dart';

import 'net_error_interceptor.dart';
import 'package:dio/dio.dart';
import 'package:connectivity/connectivity.dart';

class HttpMan {
  static const int connetTimeout = 10000;
  static const int receiveTimeout = 10000;
  late Dio _dio;
  CancelToken cancelToken = CancelToken();

  factory HttpMan() => _getInstance();
  static HttpMan get instance => _getInstance();

  static HttpMan? _instance;

  static HttpMan _getInstance() {
    _instance ??= HttpMan._internal();
    return _instance!;
  }

  HttpMan._internal() {
    BaseOptions options = BaseOptions(
        connectTimeout: connetTimeout, receiveTimeout: receiveTimeout);
    _dio = Dio(options);
    _dio.interceptors.add(NetRequestInterceptor());
    _dio.interceptors.add(NetErrorInterceptor());
  }

  Future<NetBaseReponse> post(
    String path, {
    Map<String, dynamic>? args,
    bool needBaseResp = true,
  }) async {
    return request(
      path,
      args: args,
      isPost: true,
      needBaseResp: needBaseResp,
    );
  }

  Future<NetBaseReponse> get(
    String path, {
    Map<String, dynamic>? args,
    bool needBaseResp = true,
  }) async {
    return request(
      path,
      args: args,
      isPost: false,
      needBaseResp: needBaseResp,
    );
  }

  Future<NetBaseReponse> request(
    String path, {
    Map<String, dynamic>? args,
    bool isPost = true,
    bool needBaseResp = true,
  }) async {
    var connectivityResult = await Connectivity().checkConnectivity();
    if (connectivityResult == ConnectivityResult.none) {
      return NetBaseReponse.code(code: NetResponseCode.networkError);
    }
    Response _response = isPost
        ? await _dio.post(
            path,
            data: args ?? {},
            cancelToken: cancelToken,
          )
        : await _dio.get(
            path,
            queryParameters: args,
            cancelToken: cancelToken,
          );
    if (!needBaseResp) {
      return NetBaseReponse.origin(data: _response.data);
    }
    if (_response.statusCode == 200) {
      return NetBaseReponse.response(res: NetReponse.fromJson(_response.data));
    } else {
      debugPrint(_response.toString());
      return NetBaseReponse.code(code: NetResponseCode.networkError);
    }
  }

  Future<NetBaseReponse> requestUri(
    Uri uri,
  ) async {
    var connectivityResult = await Connectivity().checkConnectivity();
    if (connectivityResult == ConnectivityResult.none) {
      return NetBaseReponse.code(code: NetResponseCode.networkError);
    }
    Response _response = await _dio.requestUri(
      uri,
      cancelToken: cancelToken,
    );
    return NetBaseReponse.origin(data: _response.data);
  }

  Future<NetBaseReponse> upload(
    String path, {
    required FormData data,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) async {
    var connectivityResult = await Connectivity().checkConnectivity();
    if (connectivityResult == ConnectivityResult.none) {
      return NetBaseReponse.code(code: NetResponseCode.networkError);
    }
    Response _response = await _dio.post(
      path,
      data: data,
      cancelToken: cancelToken,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
    );
    if (_response.statusCode == 200) {
      return NetBaseReponse.response(res: NetReponse.fromJson(_response.data));
    } else {
      return NetBaseReponse.code(code: NetResponseCode.networkError);
    }
  }

/*
   * 取消请求
   *
   * 同一个cancel token 可以用于多个请求，当一个cancel token取消时，所有使用该cancel token的请求都会被取消。
   * 所以参数可选
   */
  void cancelRequest({CancelToken? token}) {
    token ?? cancelToken.cancel('canceled');
  }
}
